namespace AI_BOTS
{
	using System;
	using System.Collections.Generic;
	public class Planet
	{
		public Planet() { }
		public Planet(PlanetWars pw, int planetID, int owner, int numShips, int growthRate, double x, double y)
		{
			this.pw = pw;
			GrowthRate = growthRate;
			NumShips = numShips;
			Owner = owner;
			PlanetID = planetID;
			X = x;
			Y = y;
		}

		public int PlanetID { get; set; }
		public int Owner { get; set; }
		public int NumShips { get; set; }
		public int GrowthRate { get; set; }
		public double X { get; set; }
		public double Y { get; set; }
		private PlanetWars pw { get; set; }

		public List<Planet> ClosestPlanets(PlanetFactory.PLANET_TYPES planetType, int? maxResults)
		{
			List<Planet> planets = PlanetFactory.FetchPlanetsByDistance(pw, this.PlanetID, planetType, true, maxResults);
			if(maxResults != null)
				return Take(planets, maxResults);

			return planets;
		}
		public List<Planet> FetchClosestWeakestPlanets(PlanetFactory.PLANET_TYPES planetType, int? maxResults)
		{
			// get planets ordered by weakest first
			List<Planet> planets = PlanetFactory.FetchPlanetsByStrength(pw, planetType, false, maxResults);

			// now sort by distance			
			planets.Sort(delegate(Planet p1, Planet p2) { return p1.NumShips.CompareTo(p2.NumShips); });

			if(maxResults != null)
				return Take(planets, maxResults);

			return planets;
		}
		public List<Planet> FetchClosestStrongestPlanets(PlanetFactory.PLANET_TYPES planetType, int? maxResults)
		{
			// get planets ordered by weakest first
			List<Planet> planets = PlanetFactory.FetchPlanetsByStrength(pw, planetType, false, maxResults);

			// now sort by distance			
			planets.Sort(delegate(Planet p1, Planet p2) { return p2.NumShips.CompareTo(p1.NumShips); });

			if(maxResults != null)
				return Take(planets, maxResults);

			return planets;
		}

		public List<Fleet> FetchOutboundFleets()
		{
			List<Fleet> fleets = new List<Fleet>();
			foreach(Fleet f in pw.MyFleets())
			{
				if(f.SourcePlanet.PlanetID == this.PlanetID)
				{
					fleets.Add(f);
				}
			}
			return fleets;
		}
		public List<Fleet> FetchInboundEnemyFleets()
		{
			List<Fleet> fleets = new List<Fleet>();
			foreach(Fleet f in pw.EnemyFleets())
			{
				if(f.DestinationPlanet.PlanetID == this.PlanetID)
				{
					fleets.Add(f);
				}
			}
			return fleets;
		}
		public List<Fleet> FetchInboundMyFleets()
		{
			List<Fleet> fleets = new List<Fleet>();
			foreach(Fleet f in pw.MyFleets())
			{
				if(f.DestinationPlanet.PlanetID == this.PlanetID)
				{
					fleets.Add(f);
				}
			}
			return fleets;
		}
		public List<Fleet> FetchInboundAllFleets()
		{
			List<Fleet> fleets = new List<Fleet>();
			foreach(Fleet f in pw.Fleets())
			{
				if(f.DestinationPlanet.PlanetID == this.PlanetID)
				{
					fleets.Add(f);
				}
			}
			return fleets;
		}

		public int TotalInboundShips
		{
			get
			{
				int ships = 0;
				List<Fleet> fleets = new List<Fleet>();
				foreach(Fleet f in this.FetchInboundAllFleets())
				{
					ships += f.NumShips;
				}
				return ships;
			}
		}
		public int TotalInboundEnemyShips
		{
			get
			{
				int inBoundShips = 0;
				List<Fleet> fleets = new List<Fleet>();
				foreach(Fleet f in this.FetchInboundEnemyFleets())
				{
					inBoundShips += f.NumShips;
				}
				return inBoundShips;
			}
		}
		public int TotalInboundMyShips
		{
			get
			{
				int damage = 0;
				List<Fleet> fleets = new List<Fleet>();
				foreach(Fleet f in this.FetchInboundMyFleets())
				{
					damage += f.NumShips;
				}
				return damage;
			}
		}

		public int TotalInboundShipDamage
		{
			get
			{
				int enemyInbound = 0;
				int myInbound = 0;
				int maxTurnsRemaining = 0;

				foreach(Fleet f in this.FetchInboundAllFleets())
				{
					if(f.TurnsRemaining > maxTurnsRemaining)
						maxTurnsRemaining = f.TurnsRemaining;

					if(f.Owner == 2)
					{
						enemyInbound += f.NumShips;
					}
					else
					{
						myInbound += f.NumShips;
					}
				}
				int growthRateOffset = this.Owner == 0 ? 0 : this.GrowthRate * maxTurnsRemaining;
				int planetShips = growthRateOffset + this.NumShips;
				planetShips = planetShips + enemyInbound;
				planetShips = planetShips - myInbound;
				return planetShips;
			}
		}

		public void RemoveShips(int ships)
		{
			NumShips -= ships;
		}
		public int NumShipsPercent(double amount)
		{
			return Convert.ToInt16(Math.Floor(this.NumShips * amount));
		}

		public bool SendEnoughShipsToTake(Planet destPlanet)
		{
			int mustSend = destPlanet.TotalInboundShipDamage + 1;			
			if(this.NumShips > mustSend)
			{
			    this.SendFleetsStandard(destPlanet, mustSend);				
			    return true;
			}
			return false;
		}
		public bool SendFleetsStandard(Planet destPlanet, int fleetsToSend)
		{
			pw.IssueOrder(this, destPlanet, fleetsToSend);
			pw.Fleets().Add(new Fleet(this.Owner, fleetsToSend, this, destPlanet, pw.Distance(this.PlanetID, destPlanet.PlanetID), pw.Distance(this.PlanetID, destPlanet.PlanetID)));
			this.RemoveShips(fleetsToSend);
			return true;
		}
		public bool SendFleetsRage(Planet destPlanet)
		{
			//int send = this.NumShips - 6;

			////foreach(Fleet f in pw.EnemyFleets)
			////{
			////    if(f.DestinationPlanet == this.planetID && f.TurnsRemaining <= 1)
			////    {
			//pw.IssueOrder(this, destPlanet, send);
			////this.RemoveShips(send);
			////        }
			////    }
			return false;
		}
		public bool WillAttackingLeaveVulnerable(Planet destPlanet, int fleetsToSend)
		{
			int InboundDamage = 0;
			int defense = 0;

			foreach(Fleet f in this.FetchInboundEnemyFleets())
			{
				defense = (f.TurnsRemaining - 1 * (this.GrowthRate));
				InboundDamage += (f.NumShips - defense);
			}
			return (this.NumShips - fleetsToSend) < InboundDamage;
		}
		private List<Planet> Take(List<Planet> planets, int? amount)
		{
			if(amount == null)
				return planets;

			List<Planet> results = new List<Planet>();
			for(int i = 0;i < amount;i++)
			{
				results.Add(planets[i]);
			}
			return results;
		}
	}
}